/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.tbp.utils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Classe responsável por formatar e manipular datas.
 * Assume-se que: dataString equivale a classe String,
 *                dataObjeto equivale a classe java.util.Date,
 *                dataBancoDeDados equivale a classe java.sql.Date.
 * @author Diego Freire Cabral
 */
public class DateUtils {

    private DateUtils() {
    }
    private static final SimpleDateFormat formatador = new SimpleDateFormat("dd/MM/yyyy");
    private static final SimpleDateFormat formatadorDataPorExtensoCompleta = new SimpleDateFormat("EEEE, dd MMMM 'de' yyyy");
    private static final SimpleDateFormat formatadorDataPorExtensoSimples = new SimpleDateFormat("dd 'de' MMMM 'de' yyyy");
    private static final SimpleDateFormat formatadorTimestamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    private static final SimpleDateFormat formatadorMes = new SimpleDateFormat("MMMM");

    public static Date dataStringParaObjeto(String arg) {
        try {
            return arg != null ? formatador.parse(arg) : null;
        } catch (ParseException ex) {
            return null;
        }
    }

    public static String dataObjetoParaString(Date arg) {
        return arg != null ? formatador.format(arg) : "";
    }

    public static java.sql.Date dataObjetoParaDataBancoDeDados(Date arg) {
        return arg != null ? new java.sql.Date(arg.getTime())
                : null;
        //new java.sql.Date(new Date().getTime());
    }

    public static Date dataBancoDeDadosParaDataObjeto(java.sql.Date arg) {
        return arg != null ? dataStringParaObjeto(formatador.format(arg)) : null;
    }

    public static String getDataHojeComoString() {
        return formatador.format(new Date());
    }

    public static String getDataComHorarioAtual() {
        Calendar c = Calendar.getInstance();
        String horario = c.get(Calendar.HOUR_OF_DAY) + ":"
                + c.get(Calendar.MINUTE)
                + ":" + c.get(Calendar.SECOND);

        return getDataHojeComoString() + " " + horario;
    }

    public static boolean validarData(String data) {
        boolean validou = false;
        String[] split = data.split("/");
        try {
            int aux = Integer.parseInt(split[0]);
            if ((aux < 1) || (aux > 31)) {
                return validou;
            }
            aux = Integer.parseInt(split[1]);
            if ((aux < 1) || (aux > 12)) {
                return validou;
            }
            aux = Integer.parseInt(split[2]);
            if (aux < 1900) {
                return validou;
            }
        } catch (NumberFormatException nfe) {
            return validou;
        }

        validou = true;
        return validou;
    }

    public static Timestamp getTempoCorrente() {
        return new Timestamp(new Date().getTime());
    }

    public static String getDataPorExtensoDetalhada(Date data) {
        return formatadorDataPorExtensoCompleta.format(data);
    }

    public static String dataParaDiaString(Date data) {
        Calendar cal = getCalendar();
        cal.setTime(data);
        return String.valueOf(cal.get(Calendar.DAY_OF_MONTH));
    }

    public static String getDataPorExtensoSimples(Date data) {
        return formatadorDataPorExtensoSimples.format(data);
    }

    public static Calendar getCalendar() {
        return Calendar.getInstance();
    }

    public static int getAnoAtual() {
        Calendar c = getCalendar();
        return c.get(Calendar.YEAR);
    }

    public static int getMesAtual() {
        Calendar c = getCalendar();
        //Atenção: o mês começa em 0
        return c.get(Calendar.MONTH);
    }

    public static Calendar getDataComoCalendar(java.sql.Date data) {
        Calendar c = Calendar.getInstance();
        c.setTime(dataBancoDeDadosParaDataObjeto(data));
        return c;
    }

    public static String formatarTimeStamp(Timestamp t) {
        if (t != null) {
            return formatadorTimestamp.format(new Date(t.getTime()));
        }
        return null;
    }

    public static String formatarTimeStamp(Date d) {
        if (d != null) {
            return formatadorTimestamp.format(d);
        }
        return null;
    }

    public static String getMesComoString(Date d) {
        return d != null ? formatadorMes.format(d) : "";
    }

    public static int comparaHojeComData(Date data) {
        try {
            String hojeStr = DateUtils.dataObjetoParaString(new Date());
            String dataStr = DateUtils.dataObjetoParaString(data);
            return hojeStr.compareTo(dataStr);
        } catch (Exception ex) {
            return -1;
        }
    }

    public static int comparaDatas(Date d1, Date d2) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(d1);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(d2);
        return d1.compareTo(d2);
    }

    public static boolean seDataAnterior(Date d1, Date d2) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(d1);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(d2);
        return d1.before(d2);
    }

    public static boolean seDataPosterior(Date d1, Date d2) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(d1);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(d2);
        return d1.after(d2);
    }

    public static String getDataPorExtensoCompleta(Date data) {
        return formatadorDataPorExtensoCompleta.format(data);
    }

    public static String addDias(Date d, int dias) {
        Calendar c = getCalendar();
        c.setTime(d);
        c.add(Calendar.DAY_OF_YEAR, dias);
        d = c.getTime();
        String data = getDataPorExtensoDetalhada(d);
        return data;
    }

    /**
     * Método para comparar as datas e retornar o numero de dias de diferença entre elas
     *
     * Compare two date and return the difference between them in days.
     *
     * @param dataInicial The lowest date
     * @param dataFinal The highest date
     *
     * @return int
     */
    public static int diferencaEmDias(java.util.Date dataInicial, java.util.Date dataFinal) {

        GregorianCalendar startTime = new GregorianCalendar();
        GregorianCalendar endTime = new GregorianCalendar();

        GregorianCalendar curTime = new GregorianCalendar();
        GregorianCalendar baseTime = new GregorianCalendar();

        startTime.setTime(dataInicial);
        endTime.setTime(dataFinal);

        int dif_multiplier = 1;

        // Verifica a ordem de inicio das datas
        if (dataInicial.compareTo(dataFinal) < 0) {
            baseTime.setTime(dataFinal);
            curTime.setTime(dataInicial);
            dif_multiplier = 1;
        } else {
            baseTime.setTime(dataInicial);
            curTime.setTime(dataFinal);
            dif_multiplier = -1;
        }

        int result_years = 0;
        int result_months = 0;
        int result_days = 0;

        // Para cada mes e ano, vai de mes em mes pegar o ultimo dia para import acumulando
        // no total de dias. Ja leva em consideracao ano bissesto
        while (curTime.get(GregorianCalendar.YEAR) < baseTime.get(GregorianCalendar.YEAR)
                || curTime.get(GregorianCalendar.MONTH) < baseTime.get(GregorianCalendar.MONTH)) {

            int max_day = curTime.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
            result_months += max_day;
            curTime.add(GregorianCalendar.MONTH, 1);

        }

        // Marca que é um saldo negativo ou positivo
        result_months = result_months * dif_multiplier;


        // Retorna a diferenca de dias do total dos meses
        result_days += (endTime.get(GregorianCalendar.DAY_OF_MONTH) - startTime.get(GregorianCalendar.DAY_OF_MONTH));

        return result_years + result_months + result_days;
    }

    /**
     * Calcula a diferença de duas datas em horas
     * <br>
     * <b>Importante:</b> Quando realiza a diferença em horas entre duas datas, este método considera os minutos restantes e os converte em fração de horas.
     * @param dataInicial
     * @param dataFinal
     * @return quantidade de horas existentes entre a dataInicial e dataFinal.
     */
    public static long diferencaEmHoras(Date dataInicial, Date dataFinal) {
        long diferenca = dataFinal.getTime() - dataInicial.getTime();
        long diferencaEmHoras = (diferenca / 1000) / 60 / 60;
        return diferencaEmHoras;
    }

    /**
     * Calcula a diferença de duas datas em minutos
     * <br>
     * <b>Importante:</b> Quando realiza a diferença em minutos entre duas datas, este método considera os segundos restantes e os converte em fração de minutos.
     * @param dataInicial
     * @param dataFinal
     * @return quantidade de minutos existentes entre a dataInicial e dataFinal.
     */
    public static long diferencaEmMinutos(Date dataInicial, Date dataFinal) {
        long diferenca = dataFinal.getTime() - dataInicial.getTime();
        long diferencaEmMinutos = (diferenca / 1000) / 60; //resultado é diferença entre as datas em minuto
        return diferencaEmMinutos;
    }

    /**
     * Calcula a diferença de duas datas em segundos
     * <br>
     * <b>Importante:</b> Quando realiza a diferença em minutos entre duas datas, este método considera os segundos restantes e os converte em fração de minutos.
     * @param dataInicial
     * @param dataFinal
     * @return quantidade de minutos existentes entre a dataInicial e dataFinal.
     */
    public static long diferencaEmSegundos(Date dataInicial, Date dataFinal) {
        long diferenca = dataFinal.getTime() - dataInicial.getTime();
        long diferencaEmSegundos = (diferenca / 1000); //resultado é diferença entre as datas em segundos
        return diferencaEmSegundos;
    }

    public static Date addHorarioAtual(Date data) {
        GregorianCalendar agora = new GregorianCalendar();
        agora.setTime(data);
        int dia = agora.get(Calendar.DAY_OF_MONTH);
        int mes = agora.get(Calendar.MONTH);
        int ano = agora.get(Calendar.YEAR);
        GregorianCalendar dataComHoras = new GregorianCalendar();
        dataComHoras.set(Calendar.DAY_OF_MONTH, dia);
        dataComHoras.set(Calendar.MONTH, mes);
        dataComHoras.set(Calendar.YEAR, ano);
        return dataComHoras.getTime();
    }
}
